/**
 * 
 */
package fr.upmc.alasca.centreCalcul.interne.machinePhysique.capteurCoeurs;

import java.util.ArrayList;
import java.util.List;

import fr.upmc.alasca.centreCalcul.interne.machinePhysique.capteurCoeurs.connectors.CapteurCoeursControleurPushConnector;
import fr.upmc.alasca.centreCalcul.interne.machinePhysique.capteurCoeurs.interfaces.CapteurCoeursControleurAbonnementI;
import fr.upmc.alasca.centreCalcul.interne.machinePhysique.capteurCoeurs.interfaces.CapteurCoeursControleurPushI;
import fr.upmc.alasca.centreCalcul.interne.machinePhysique.capteurCoeurs.interfaces.CapteurCoeursMachinePhysiqueI;
import fr.upmc.alasca.centreCalcul.interne.machinePhysique.capteurCoeurs.ports.CapteurCoeursControleurAbonnementInboundPort;
import fr.upmc.alasca.centreCalcul.interne.machinePhysique.capteurCoeurs.ports.CapteurCoeursControleurPushOutboundPort;
import fr.upmc.alasca.centreCalcul.interne.machinePhysique.capteurCoeurs.ports.CapteurCoeursMachinePhysiqueInboundPort;
import fr.upmc.alasca.centreCalcul.objets.CoeurParam;
import fr.upmc.components.AbstractComponent;

/**
 * @author Antoine Lavaire, Sabri Labassi, Thibaut Fleury, Ryme Fantazi
 */
public	class	CapteurCoeurs
extends			AbstractComponent
implements		CapteurCoeursControleurAbonnementI, CapteurCoeursMachinePhysiqueI
{
	/* ------------------------------------------------------------- ATTRIBUT */
	private	String											uri;
	private String											uriMachinePhysique;
	private	List<CapteurCoeursControleurPushOutboundPort>	portsAbonnes;




	/* --------------------------------------------------------- CONSTRUCTEUR */
	public	CapteurCoeurs
	(
		String	p_uriMachinePhysique
	) throws	Exception
	{	
		super(false);
		
		portsAbonnes = new ArrayList<>();
		uriMachinePhysique = p_uriMachinePhysique;
		uri = p_uriMachinePhysique + "_Capteur";
		
		// Création du port permettant de récupérer les infos depuis la MP
		this.addOfferedInterface(CapteurCoeursMachinePhysiqueI.class);
		CapteurCoeursMachinePhysiqueInboundPort ccmp_port =
				new CapteurCoeursMachinePhysiqueInboundPort(uri + "_MachineP", this);
		this.addPort(ccmp_port);
		ccmp_port.localPublishPort();
		
		// Création du port permettant d'offrir la possibilité de s'abonner au capteur
		this.addOfferedInterface(CapteurCoeursControleurAbonnementI.class);
		CapteurCoeursControleurAbonnementInboundPort ccca_port = 
				new CapteurCoeursControleurAbonnementInboundPort(uri + "_Abonnement",  this);
		this.addPort(ccca_port);
		ccca_port.localPublishPort();
		
		this.addRequiredInterface(CapteurCoeursControleurPushI.class);
	}




	/* -------------------------------------------------------------- METHODE */
	@Override
	public	void	abonner
	(
		String	p_uriCallback
	) throws	Exception
	{
		CapteurCoeursControleurPushOutboundPort cccpop =
				new CapteurCoeursControleurPushOutboundPort(uri + p_uriCallback, this);
		
		cccpop.localPublishPort();
		this.addPort(cccpop);
		cccpop.doConnection(p_uriCallback,
				CapteurCoeursControleurPushConnector.class.getCanonicalName());
		
		synchronized (portsAbonnes) {
			portsAbonnes.add(cccpop);
		}
	}


	@Override
	public	void	modificationCoeur
	(
		List<CoeurParam>	p_coeurs
	) throws	Exception
	{
		List<CapteurCoeursControleurPushOutboundPort> trash;
		
		synchronized (portsAbonnes) {
			trash = new ArrayList<>();

			for(CapteurCoeursControleurPushOutboundPort port : portsAbonnes) {
				// Si le port n'est plus connecté, alors c'est que le contrôleur
				// d'application a initié la déconnexion et ne veut plus recevoir
				// les notifications
				if (!port.connected())
					trash.add(port);
				else
					port.pushCoeursConfig(p_coeurs, uriMachinePhysique);
			}
			
			// Suppression des ports déconnectés
			for (CapteurCoeursControleurPushOutboundPort portToDelete : trash) {
				portsAbonnes.remove(portToDelete);
			}
		}
	}
}
